package com.shenzw.common.sign;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import sun.misc.BASE64Decoder;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Collections;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.stream.Collectors;

/**
 * @description: 加签切面
 * @author: shenzw
 * @date: 2024/10/26
 */
@Aspect
@Component
@Slf4j
public class SignAspect {

    // 私钥字符串
    private static final String PRIVATE_KEY_STR = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBANonNWMLkrqRtLZg\n" +
            "TZ+IOzofykEkUMYRiqokkL0jcTQRuvkWyh90iZXl5Z0FJ4APBxH2mk1uk5F1mZxf\n" +
            "pKKmiArH09floA7gY96yuhV46z3XGssQa39qu15byJIP5loYNRVXf7BwR1yL94K8\n" +
            "WVzk9S5kmi4zZdloMrgWDYhFN8NdAgMBAAECgYA9bz1Bn0i68b2KfqRdgOfs/nbe\n" +
            "0XNN1DLQp2t7WDfRCg01iI1zPkZgyFVZWtI85f5/uIrLs5ArLosL1oNuqqc0nNne\n" +
            "CvJK+ZxvA98Hx3ZqYTzDnleR054YhofL5awbhSciYVic204DOG1rhSsYWMqtX7J7\n" +
            "3geoWL7TYdMfYXcCAQJBAPMMKsz6ZJh98EeQ1tDG5gpAGWFQkYNrxZDelP/LjeO0\n" +
            "TP3XkQnIpcaZoCs7V/rRGRGMWwQ2BUdc/01in89ZZ5ECQQDlx2oBc1CtOAm2UAhN\n" +
            "1xWrPkZWENQ53wTrwXO4qbTGDfBKon0AehLlGCSqxQ71aufLkNO7ZlX0IHTAlnk1\n" +
            "TvENAkAGSEQ69CXxgx/Y2beTwfBkR2/gghKg0QJUUkyLqBlMz3ZGAXJwTE1sqr/n\n" +
            "HiuSAiGhwH0ByNuuEotO1sPGukrhAkAMK26a2w+nzPL+u+hkrwKPykGRZ1zGH+Cz\n" +
            "19AYNKzFXJGgclCqiMydY5T1knBDYUEbj/UW1Mmyn1FvrciHoUG1AkAEMEIuDauz\n" +
            "JabEAU08YmZw6OoDGsukRWaPfjOEiVhH88p00veM1R37nwhoDMGyEGXVeVzNPvk7\n" +
            "cELg28MSRzCK";

    @Around("@annotation(signatureAnnotation)")
    public Object sign(ProceedingJoinPoint joinPoint, SignatureAnnotation signatureAnnotation) throws Throwable {
        // 获取方法参数
        Object[] args = joinPoint.getArgs();
        String plain = (String) args[0]; // 假设第一个参数为原始报文

        // 将参数转化为Map（假设原始报文为JSON格式或类似结构）
        Map<String, String> params = parseToMap(plain);

        params.put("ad", ""); // 模拟空数据
        params.put("employeeId", "3838438"); // 塞入员工号

        // 筛选有效参数，去除空值
        Map<String, String> filteredParams = filterEmptyParams(params);

        // 排序
        SortedMap<String, String> sortedParams = new TreeMap<>(filteredParams);

        // 拼接
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : sortedParams.entrySet()) {
            sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
        }
        // 去除最后一个&符号
        String signString = sb.substring(0, sb.length() - 1);

        System.out.println("经过筛选有效参数 (去除空参)-> 排序 -> 拼接 -> 加签的入参: " + signString);

        // 调用加签方法
        byte[] signature = sign(signString);

        // 将签名添加到原始参数（或返回值）
        return joinPoint.proceed(new Object[]{signString, signature}); // 加签前的数据➕签名
    }

    /**
     * 筛选有效参数，去除空值
     */
    private Map<String, String> filterEmptyParams(Map<String, String> params) {
        return params.entrySet()
                .stream()
                .filter(entry -> entry.getValue() != null && !entry.getValue().isEmpty())
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
    }

    private Map<String, String> parseToMap(String plain) {
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            // 将 JSON 字符串解析为 Map
            return objectMapper.readValue(plain, Map.class);
        } catch (JsonProcessingException e) {
            // 处理解析错误
            log.error("解析原始报文失败: {}", e.getMessage());
            return Collections.emptyMap(); // 返回空 Map
        }
    }

    /**
     * 加签方法
     *
     * @param plain 原始报文
     * @return 签名结果
     */
    private static byte[] sign(String plain) {
        try {
            Signature signature = Signature.getInstance("SHA256WithRSA");
            PrivateKey privateKey = getPrivateKey(PRIVATE_KEY_STR);
            signature.initSign(privateKey);
            signature.update(plain.getBytes(StandardCharsets.UTF_8));
            return signature.sign();
        } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
            log.error("加签失败", e);
        }
        return null;
    }


    private static PrivateKey getPrivateKey(String privateKeyStr) {
        PrivateKey privateKey = null;
        PKCS8EncodedKeySpec priPKCS8;
        try {
            priPKCS8 = new PKCS8EncodedKeySpec(new BASE64Decoder().decodeBuffer(privateKeyStr));
            KeyFactory keyf = KeyFactory.getInstance("RSA");
            privateKey = keyf.generatePrivate(priPKCS8);
        } catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException e) {
            log.error("生成私钥异常", e);
        }
        return privateKey;
    }
}

